#include <windows.h>
#include <commdlg.h>
#include <stdio.h>
#include <math.h>
#include <string.h>
#include <dir.h>
#include <dos.h>
#include "resid.h"
#include "remez.h"

HACCEL hCurrAccel = (HACCEL)0;
HWND hCurrDialog = (HWND)0;
HWND hMainWnd;
HINSTANCE hInst;

int fDoPaint = 0;

#if WINVER < 0x30a
    typedef FARPROC DLGPROC_t;
#else
    typedef DLGPROC DLGPROC_t;
#endif

class DlgProcInstance
{
  public:
    DlgProcInstance(BOOL CALLBACK _export (*pFunc)(HWND, UINT, WPARAM, LPARAM)) :
      instance((DLGPROC_t)MakeProcInstance((FARPROC)pFunc, hInst))
    {
    }
    ~DlgProcInstance()
    {
      FreeProcInstance((FARPROC)instance);
    }
    operator DLGPROC_t()
    {
      return (instance);
    }
  private:
    DLGPROC_t instance;
};

DLGPROC_t lpfnInstIterDlgProc;

static const char pcszClassName[] = "RemezWndClass";
static const char pcszAppName[]   = "Projektowanie filtrów FIR";

static void (*BkgrProc)(void) = NULL;

static int iFilterType;
static int iFilterLength;
static int iFilterBandsNo;

static double MinY = -100, MaxY = 5;

#pragma argsused

BOOL CALLBACK _export GetFIRTypeDlgProc(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam)
{
  switch (wMsg)
  {
    case WM_INITDIALOG:
      SendDlgItemMessage(hWnd, D1001_RADIO1, BM_SETCHECK, 1, 0);
      SendDlgItemMessage(hWnd, D1001_RADIO2, BM_SETCHECK, 0, 0);
      SendDlgItemMessage(hWnd, D1001_RADIO3, BM_SETCHECK, 0, 0);
      SendDlgItemMessage(hWnd, D1001_EDIT1, EM_LIMITTEXT, 20, 0);
      SendDlgItemMessage(hWnd, D1001_EDIT2, EM_LIMITTEXT, 20, 0);
      SetDlgItemText(hWnd, D1001_EDIT1, "");
      SetDlgItemText(hWnd, D1001_EDIT2, "");
      return (TRUE);
    case WM_COMMAND:
      switch (wParam)
      {
        case IDOK:
          int i;
          for(i = D1001_RADIO1; i <= D1001_RADIO3; i++)
            if(SendDlgItemMessage(hWnd, i, BM_GETCHECK, 0, 0))
            {
              iFilterType = i - D1001_RADIO1;
              break;
            }
          iFilterLength = GetDlgItemInt(hWnd, D1001_EDIT1, (BOOL FAR *)&i, FALSE);
          if(!i || !iFilterLength)
          {
            MessageBeep(MB_ICONHAND);
            MessageBox(hWnd, "Nieprawidłowa długość filtru", NULL, MB_OK | MB_ICONHAND);
            SetFocus(GetDlgItem(hWnd, D1001_EDIT1));
            SendDlgItemMessage(hWnd, D1001_EDIT1, EM_SETSEL, 0, MAKELPARAM(0, -1));
            return (TRUE);
          }
          if(iFilterType != 2)
          {
            iFilterBandsNo = GetDlgItemInt(hWnd, D1001_EDIT2, (BOOL FAR *)&i, FALSE);
            if(!i || !iFilterBandsNo)
            {
              MessageBeep(MB_ICONHAND);
              MessageBox(hWnd, "Nieprawidłowa liczba pasm filtru", NULL, MB_OK | MB_ICONHAND);
              SetFocus(GetDlgItem(hWnd, D1001_EDIT2));
              SendDlgItemMessage(hWnd, D1001_EDIT2, EM_SETSEL, 0, MAKELPARAM(0, -1));
              return (TRUE);
            }
          }
          else
            iFilterBandsNo = 1;
          EndDialog(hWnd, 1);
          return (TRUE);
        case IDCANCEL:
          EndDialog(hWnd, 0);
          return (TRUE);
      }
      break;
  }
  return (FALSE);
}

static double fBandData[4];

#pragma argsused

BOOL CALLBACK _export GetBandDlgProc(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam)
{
  int i;
  char buffer[21];
  switch (wMsg)
  {
    case WM_INITDIALOG:
      for(i = D1002_EDIT1; i <= D1002_EDIT4; i++)
      {
        SendDlgItemMessage(hWnd, i, EM_LIMITTEXT, 20, 0);
        SetDlgItemText(hWnd, i, "");
      }
      sprintf(buffer, "Parametry pasma %d", (int)lParam);
      SendMessage(hWnd, WM_SETTEXT, 0, (LPARAM)(LPCSTR)buffer);
      return (TRUE);
    case WM_COMMAND:
      switch (wParam)
      {
        case IDOK:
          for(i = D1002_EDIT1; i <= D1002_EDIT4; i++)
          {
            GetDlgItemText(hWnd, i, buffer, 20);
            if(!buffer[0] || !sscanf(buffer, "%lf", &fBandData[i - D1002_EDIT1]))
              if(stricmp(buffer, "pi") == 0)
                fBandData[i - D1002_EDIT1] = M_PI;
              else
              {
                MessageBeep(MB_ICONHAND);
                MessageBox(hWnd, "Nieprawidłowa liczba", NULL, MB_OK | MB_ICONHAND);
                SetFocus(GetDlgItem(hWnd, i));
                SendDlgItemMessage(hWnd, i, EM_SETSEL, 0, MAKELPARAM(0, -1));
                return (TRUE);
              }
          }
          EndDialog(hWnd, 1);
          return (TRUE);
        case IDCANCEL:
          EndDialog(hWnd, 0);
          return (TRUE);
      }
      break;
  }
  return (FALSE);
}

#pragma argsused

BOOL CALLBACK _export GetDiffDlgProc(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam)
{
  char buffer[21];
  switch (wMsg)
  {
    case WM_INITDIALOG:
      SendDlgItemMessage(hWnd, D1003_EDIT1, EM_LIMITTEXT, 20, 0);
      SetDlgItemText(hWnd, D1003_EDIT1, "");
      return (TRUE);
    case WM_COMMAND:
      switch (wParam)
      {
        case IDOK:
          GetDlgItemText(hWnd, D1003_EDIT1, buffer, 20);
          if(!buffer[0] || !sscanf(buffer, "%lf", &fBandData[1]))
            if(stricmp(buffer, "pi") == 0)
              fBandData[1] = M_PI;
            else
            {
              MessageBeep(MB_ICONHAND);
              MessageBox(hWnd, "Nieprawidłowa liczba", NULL, MB_OK | MB_ICONHAND);
              SetFocus(GetDlgItem(hWnd, D1003_EDIT1));
              SendDlgItemMessage(hWnd, D1003_EDIT1, EM_SETSEL, 0, MAKELPARAM(0, -1));
              return (TRUE);
            }
          EndDialog(hWnd, 1);
          return (TRUE);
        case IDCANCEL:
          EndDialog(hWnd, 0);
          return (TRUE);
      }
      break;
  }
  return (FALSE);
}

static Filter FIR;
static SearchTypes searchtype = UseSelectCubic;
static FilterTypes filtertype;

#pragma argsused

BOOL CALLBACK _export GetSearchTypeDlgProc(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam)
{
  switch (wMsg)
  {
    case WM_INITDIALOG:
      SendDlgItemMessage(hWnd, D1004_RADIO1, BM_SETCHECK, searchtype == ExhaustiveOnly, 0);
      SendDlgItemMessage(hWnd, D1004_RADIO2, BM_SETCHECK, searchtype == UseSelective, 0);
      SendDlgItemMessage(hWnd, D1004_RADIO3, BM_SETCHECK, searchtype == UseSelectCubic, 0);
      return (TRUE);
    case WM_COMMAND:
      switch (wParam)
      {
        case IDOK:
          searchtype = (int)SendDlgItemMessage(hWnd, D1004_RADIO1, BM_GETCHECK, 0, 0) ? ExhaustiveOnly :
                       (int)SendDlgItemMessage(hWnd, D1004_RADIO2, BM_GETCHECK, 0, 0) ? UseSelective : UseSelectCubic;
          EndDialog(hWnd, 1);
          return (TRUE);
        case IDCANCEL:
          EndDialog(hWnd, 0);
          return (TRUE);
      }
      break;
  }
  return (FALSE);
}

static unsigned int uMaxIter = 20;

#pragma argsused

BOOL CALLBACK _export GetMaxIterDlgProc(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam)
{
  BOOL bf;
  unsigned int i;
  switch (wMsg)
  {
    case WM_INITDIALOG:
      SetDlgItemInt(hWnd, D1005_EDIT1, uMaxIter, 0);
      return (TRUE);
    case WM_COMMAND:
      switch (wParam)
      {
        case IDOK:
          i = GetDlgItemInt(hWnd, D1005_EDIT1, &bf, 0);
          if(bf)
          {
            uMaxIter = i;
            EndDialog(hWnd, 1);
          }
          else
          {
            MessageBeep(MB_ICONHAND);
            MessageBox(hWnd, "Nieprawidłowa liczba", NULL, MB_OK | MB_ICONHAND);
            SetFocus(GetDlgItem(hWnd, D1005_EDIT1));
            SendDlgItemMessage(hWnd, D1005_EDIT1, EM_SETSEL, 0, MAKELPARAM(0, -1));
          }
          return (TRUE);
        case IDCANCEL:
          EndDialog(hWnd, 0);
          return (TRUE);
      }
      break;
  }
  return (FALSE);
}

Vector H;

#pragma argsused

BOOL CALLBACK _export IterDlgProc(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam)
{
  switch(wMsg)
  {
    case WM_INITDIALOG:
      return (TRUE);
    case WM_COMMAND:
      SendMessage(hWnd, WM_CLOSE, 0, 0);
      return (TRUE);
    case WM_CLOSE:
      BkgrProc = NULL;
      hCurrDialog = NULL;
      EnableMenuItem(GetMenu(hMainWnd), IDM_COEFFS, MF_BYCOMMAND | MF_ENABLED);
      EnableMenuItem(GetMenu(hMainWnd), IDM_PRINT, MF_BYCOMMAND | MF_ENABLED);
      H = CalcH();
      fDoPaint = 1;
      InvalidateRect(hMainWnd, NULL, 1);
      DestroyWindow(hWnd);
      return (TRUE);
  }
  return (FALSE);
}

#pragma argsused

BOOL CALLBACK _export GetGridDlgProc(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam)
{
  BOOL bf;
  unsigned int i;
  switch (wMsg)
  {
    case WM_INITDIALOG:
      SetDlgItemInt(hWnd, D1007_EDIT1, S, 0);
      return (TRUE);
    case WM_COMMAND:
      switch (wParam)
      {
        case IDOK:
          i = GetDlgItemInt(hWnd, D1007_EDIT1, &bf, 0);
          if(bf)
          {
            S = i;
            EndDialog(hWnd, 1);
          }
          else
          {
            MessageBeep(MB_ICONHAND);
            MessageBox(hWnd, "Nieprawidłowa liczba", NULL, MB_OK | MB_ICONHAND);
            SetFocus(GetDlgItem(hWnd, D1007_EDIT1));
            SendDlgItemMessage(hWnd, D1007_EDIT1, EM_SETSEL, 0, MAKELPARAM(0, -1));
          }
          return (TRUE);
        case IDCANCEL:
          EndDialog(hWnd, 0);
          return (TRUE);
      }
      break;
  }
  return (FALSE);
}

#pragma argsused

BOOL CALLBACK _export GetReqQDlgProc(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam)
{
  double temp;
  char buffer[80];
  switch (wMsg)
  {
    case WM_INITDIALOG:
      sprintf(buffer, "%lg", (double)RequiredQ);
      SetDlgItemText(hWnd, D1008_EDIT1, buffer);
      return (TRUE);
    case WM_COMMAND:
      switch (wParam)
      {
        case IDOK:
          GetDlgItemText(hWnd, D1008_EDIT1, buffer, 79);
          if(sscanf(buffer, "%lg", &temp))
          {
            RequiredQ = temp;
            EndDialog(hWnd, 1);
          }
          else
          {
            MessageBeep(MB_ICONHAND);
            MessageBox(hWnd, "Nieprawidłowa liczba", NULL, MB_OK | MB_ICONHAND);
            SetFocus(GetDlgItem(hWnd, D1007_EDIT1));
            SendDlgItemMessage(hWnd, D1007_EDIT1, EM_SETSEL, 0, MAKELPARAM(0, -1));
          }
          return (TRUE);
        case IDCANCEL:
          EndDialog(hWnd, 0);
          return (TRUE);
      }
      break;
  }
  return (FALSE);
}

void SaveOutput(char *pszFileName)
{
  FILE *output;
  int i;
  output = fopen(pszFileName, "wt");
  if(output)
  {
    fprintf(output, "Dane filtru:\n");
    fprintf(output, "Filter length\t= %d\n", iFilterLength);
    fprintf(output, "Filter type\t= %s\n",
      filtertype == OddSymetrical ? "OddSymetrical" :
      filtertype == OddAntysymetrical ? "OddAntysymetrical" :
      filtertype == EvenSymetrical ? "EvenSymetrical" :
      filtertype == EvenAntysymetrical ? "EvenAntysymetrical" :
      filtertype == OddDifferentiator ? "OddDifferentiator" : "");
    fprintf(output, "Search type\t= %s\n",
      searchtype == ExhaustiveOnly ? "ExhaustiveOnly" :
      searchtype == UseSelective ? "UseSelective" :
      searchtype == UseSelectCubic ? "UseSelectCubic" : "");
    fprintf(output, "Bands\t\t= %d\n", iFilterBandsNo);
    for(i = 1; i <= iFilterBandsNo; i++)
    {
      fprintf(output, "Lower edge %d\t= %lg\n", i, (double)FIR[i].GetLow());
      fprintf(output, "Upper edge %d\t= %lg\n", i, (double)FIR[i].GetHigh());
      fprintf(output, "Transmitance %d\t= %lg\n", i, (double)FIR[i].GetTrans());
      fprintf(output, "Error %d\t\t= %lg\n", i, (double)FIR[i].GetErrorRatio());
    }
    fprintf(output, "Grid\t\t= %u\n", S);
    fprintf(output, "Required Q\t= %lg\n", (double)RequiredQ);
    fprintf(output, "\nWspolczynniki filtru:\n");
    for(i = Lo(H); i <= Hi(H); i++)
      fprintf(output, "h[%i]\t= %lg\n", i, (double)H[i]);
    fclose(output);
  }
  else
  {
    char buffer[512];
    sprintf(buffer, "Blad przy otwieraniu pliku %s", pszFileName);
    MessageBeep(MB_ICONHAND);
    MessageBox(hMainWnd, buffer, NULL, MB_OK | MB_ICONHAND);
  }
}

#pragma argsused

BOOL CALLBACK _export CoeffsDlgProc(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam)
{
  if(wMsg == WM_INITDIALOG)
  {
    int i;
    char buffer[128];
    for(i = Lo(H); i <= Hi(H); i++)
    {
      sprintf(buffer, "h[%u]\t= %lg", i, (double)H[i]);
      SendDlgItemMessage(hWnd, D1009_LIST1, LB_INSERTSTRING, -1, (LPARAM)(LPCSTR)buffer);
    }
    return (TRUE);
  }
  if(wMsg == WM_COMMAND && wParam == IDOK)
  {
    EndDialog(hWnd, 0);
    return (TRUE);
  }
  if(wMsg == WM_COMMAND && wParam == D1009_BUTTON1)
  {
    OPENFILENAME ofn;
    char szFileName[80] = "filtr.wyn";
    memset(&ofn, 0, sizeof(ofn));
    ofn.lStructSize       = sizeof(ofn);
    ofn.hwndOwner         = hWnd;
    ofn.hInstance         = hInst;
    ofn.lpstrFile         = szFileName;
    ofn.nMaxFile          = sizeof(szFileName);
    ofn.Flags             = OFN_HIDEREADONLY | OFN_PATHMUSTEXIST | OFN_OVERWRITEPROMPT;
    ofn.lpstrDefExt       = "wyn";
    ofn.lpstrTitle        = "Zachowaj wynik jako:";
    if(GetSaveFileName(&ofn))
      SaveOutput(szFileName);
    return (TRUE);
  }
  return (FALSE);
}

#pragma argsused

BOOL CALLBACK _export AboutDlgProc(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam)
{
  if(wMsg == WM_COMMAND && wParam == IDOK)
  {
    EndDialog(hWnd, 0);
    return (TRUE);
  }
  if(wMsg == WM_INITDIALOG)
    return (TRUE);
  return (FALSE);
}

static char *pszFileName = NULL;
static const char pcszUntitled[] = "UNTITLED.FIR";
static const char szFilter[] = "Pliki filtrów [*.fir]\0*.fir\0Wszystkie pliki [*.*]\0*.*\0";

int SaveFileName(char *pszFileName, int nMaxFile, DWORD Flags = 0)
{
  OPENFILENAME ofn;
  assert(pszFileName);
  memset(&ofn, 0, sizeof(ofn));
  ofn.lStructSize       = sizeof(ofn);
  ofn.hwndOwner         = hMainWnd;
  ofn.hInstance         = hInst;
  ofn.lpstrFilter       = szFilter;
  ofn.nFilterIndex      = 1;
  ofn.lpstrFile         = pszFileName;
  ofn.nMaxFile          = nMaxFile;
  ofn.Flags             = OFN_HIDEREADONLY | OFN_PATHMUSTEXIST | Flags;
  ofn.lpstrDefExt       = "fir";
  return(GetSaveFileName(&ofn));
}

void SaveFile(char *pszFileName)
{
  FILE *output;
  int i;
  output = fopen(pszFileName, "wt");
  if(output)
  {
    fprintf(output, "Filter length\t= %d\n", iFilterLength);
    fprintf(output, "Filter type\t= %s\n",
      filtertype == OddSymetrical ? "OddSymetrical" :
      filtertype == OddAntysymetrical ? "OddAntysymetrical" :
      filtertype == EvenSymetrical ? "EvenSymetrical" :
      filtertype == EvenAntysymetrical ? "EvenAntysymetrical" :
      filtertype == OddDifferentiator ? "OddDifferentiator" : "");
    fprintf(output, "Search type\t= %s\n",
      searchtype == ExhaustiveOnly ? "ExhaustiveOnly" :
      searchtype == UseSelective ? "UseSelective" :
      searchtype == UseSelectCubic ? "UseSelectCubic" : "");
    fprintf(output, "Bands\t\t= %d\n", iFilterBandsNo);
    for(i = 1; i <= iFilterBandsNo; i++)
    {
      fprintf(output, "Lower edge %d\t= %lg\n", i, (double)FIR[i].GetLow());
      fprintf(output, "Upper edge %d\t= %lg\n", i, (double)FIR[i].GetHigh());
      fprintf(output, "Transmitance %d\t= %lg\n", i, (double)FIR[i].GetTrans());
      fprintf(output, "Error %d\t\t= %lg\n", i, (double)FIR[i].GetErrorRatio());
    }
    fprintf(output, "Grid\t\t= %u\n", S);
    fprintf(output, "Required Q\t= %lg\n", (double)RequiredQ);
    fclose(output);
  }
  else
  {
    char buffer[512];
    sprintf(buffer, "Blad przy otwieraniu pliku %s", pszFileName);
    MessageBeep(MB_ICONHAND);
    MessageBox(hMainWnd, buffer, NULL, MB_OK | MB_ICONHAND);
  }
}

int OpenFileName(char *pszFileName, int nMaxFile, DWORD Flags = 0)
{
  OPENFILENAME ofn;
  assert(pszFileName);
  pszFileName[0] = 0;
  memset(&ofn, 0, sizeof(ofn));
  ofn.lStructSize       = sizeof(ofn);
  ofn.hwndOwner         = hMainWnd;
  ofn.hInstance         = hInst;
  ofn.lpstrFilter       = szFilter;
  ofn.nFilterIndex      = 1;
  ofn.lpstrFile         = pszFileName;
  ofn.nMaxFile          = nMaxFile;
  ofn.Flags             = OFN_HIDEREADONLY | OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | Flags;
  ofn.lpstrDefExt       = "fir";
  return(GetOpenFileName(&ofn));
}

void OpenFile(char *pszFileName)
{
  FILE *input;
  int i;
  char buffer[512];
  Filter TempFIR;
  SearchTypes st;
  FilterTypes ft;
  int flen, fband;
  char *p;
  input = fopen(pszFileName, "rt");
  if(input)
  {
    double temp;
    if(fscanf(input, "Filter length = %d \n", &flen) != 1)
      goto Error;
    if(fscanf(input, "Filter type = %s \n", buffer) != 1)
      goto Error;
    if(strcmp(buffer, "OddSymetrical") == 0)
      ft = OddSymetrical;
    else
      if(strcmp(buffer, "OddAntysymetrical") == 0)
        ft = OddAntysymetrical;
      else
        if(strcmp(buffer, "EvenSymetrical") == 0)
          ft = EvenSymetrical;
        else
          if(strcmp(buffer, "EvenAntysymetrical") == 0)
            ft = EvenAntysymetrical;
          else
            if(strcmp(buffer, "OddDifferentiator") == 0)
              ft = OddDifferentiator;
            else
              goto Error;
    if(fscanf(input, "Search type = %s \n", buffer) != 1)
      goto Error;
    if(strcmp(buffer, "ExhaustiveOnly") == 0)
      st = ExhaustiveOnly;
    else
      if(strcmp(buffer, "UseSelective") == 0)
        st = UseSelective;
      else
        if(strcmp(buffer, "UseSelectCubic") == 0)
          st = UseSelectCubic;
        else
          goto Error;
    if(fscanf(input, "Bands = %d \n", &fband) != 1)
      goto Error;
    TempFIR.SetNoBands(fband);
    for(i = 1; i <= fband; i++)
    {
      sprintf(buffer, "Lower edge %d = %%lg \n", i);
      if(fscanf(input, buffer, &temp) != 1)
        goto Error;
      TempFIR[i].SetLow(temp);
      sprintf(buffer, "Upper edge %d = %%lg \n", i);
      if(fscanf(input, buffer, &temp) != 1)
        goto Error;
      TempFIR[i].SetHigh(temp);
      sprintf(buffer, "Transmitance %d = %%lg \n", i);
      if(fscanf(input, buffer, &temp) != 1)
        goto Error;
      TempFIR[i].SetTrans(temp);
      sprintf(buffer, "Error %d = %%lg \n", i);
      if(fscanf(input, buffer, &temp) != 1)
        goto Error;
      TempFIR[i].SetErrorRatio(temp);
    }
    if(fscanf(input, "Grid = %u \n", &i) == 1)
      S = (unsigned)i;
    if(fscanf(input, "Required Q\t= %lg \n", &temp) == 1)
      RequiredQ = (Float)temp;
    fclose(input);
    searchtype = st;
    filtertype = ft;
    FIR = TempFIR;
    iFilterBandsNo = fband;
    iFilterLength = flen;
    if(!(p = strrchr(pszFileName, '\\')))
      p = pszFileName;
    else
      p++;
    if(::pszFileName)
      delete ::pszFileName;
    ::pszFileName = new char[strlen(p) + 1];
    strcpy(::pszFileName, p);
    strcpy(buffer, "Projektowany filtr: ");
    strcat(buffer, p);
    SendMessage(hMainWnd, WM_SETTEXT, 0, (LPARAM)(LPCSTR)buffer);
    EnableMenuItem(GetMenu(hMainWnd), IDM_START, MF_BYCOMMAND | MF_ENABLED);
    EnableMenuItem(GetMenu(hMainWnd), IDM_SAVE, MF_BYCOMMAND | MF_ENABLED);
    EnableMenuItem(GetMenu(hMainWnd), IDM_SAVEAS, MF_BYCOMMAND | MF_ENABLED);
  }
  else
  {
    sprintf(buffer, "Blad przy otwieraniu pliku %s", pszFileName);
    MessageBeep(MB_ICONHAND);
    MessageBox(hMainWnd, buffer, NULL, MB_OK | MB_ICONHAND);
  }
  return;
  Error:
  sprintf(buffer, "Blad przy odczycie danych z pliku %s", pszFileName);
  MessageBeep(MB_ICONHAND);
  MessageBox(hMainWnd, buffer, NULL, MB_OK | MB_ICONHAND);
  return;
}

int FileExist(const char *pszFileName)
{
  ffblk ff;
  return (findfirst(pszFileName, &ff, FA_RDONLY | FA_HIDDEN | FA_SYSTEM | FA_ARCH) == 0);
}

unsigned int uIteration;

void BackgroundTask(void)
{
  int i;
  char buffer[80];
  if(uIteration++ <= uMaxIter)
    i = RemezIteration(searchtype);
  if(uIteration > uMaxIter || i == 0)
  {
    BkgrProc = NULL;
    SetDlgItemText(hCurrDialog, D1006_BUTTON1, "OK");
  }
  else
    SetDlgItemInt(hCurrDialog, D1006_STATIC1, uIteration, 0);
  sprintf(buffer, "%lg", fabs(Delta));
  SetDlgItemText(hCurrDialog, D1006_STATIC2, buffer);
  sprintf(buffer, "%lg", (double)Q);
  SetDlgItemText(hCurrDialog, D1006_STATIC3, buffer);
}

static double WorldX1, WorldY1, WorldX2, WorldY2;
static int ScrX1, ScrY1, ScrX2, ScrY2;

void SetWorld(double x1, double y1, double x2, double y2)
{
  WorldX1 = x1;
  WorldY1 = y1;
  WorldX2 = x2;
  WorldY2 = y2;
}

void SetScreen(int x1, int y1, int x2, int y2)
{
  ScrX1 = x1;
  ScrY1 = y1;
  ScrX2 = x2;
  ScrY2 = y2;
}

int World2ScrX(double x)
{
  return ((x - WorldX1) * (ScrX2 - ScrX1) / (WorldX2 - WorldX1) + ScrX1);
}

int World2ScrY(double y)
{
  return ((y - WorldY1) * (ScrY1 - ScrY2) / (WorldY2 - WorldY1) + ScrY2);
}

double Scr2WorldX(int x)
{
  return ((x - ScrX1) * (WorldX2 - WorldX1) / (ScrX2 - ScrX1) + WorldX1);
}

double Scr2WorldY(int y)
{
  return ((y - ScrY1) * (WorldY1 - WorldY2) / (ScrY2 - ScrY1) + WorldY2);
}

static inline Float near CplxAbs(Float re, Float im)
{
  return (sqrt(re * re + im * im));
}

Float MFIR(const Vector &h, Float x)
{
  assert(x >= 0 && x <= M_PI);
  Float c2 = 2 * cos(x), x1, x2, x3;
  int k;
  for(k = Lo(h), x1 = x2 = 0; k <= Hi(h); k++)
  {
    x3 = h[k] - x1 + c2 * x2;
    x1 = x2;
    x2 = x3;
  }
  return (CplxAbs(x2 - 0.5 * c2 * x1, sin(x) * x1));
}

inline Float lnMFIR(const Vector &h, Float x)
{
  Float a = MFIR(h, x);
  return (Eq(a, 0) ? -1e10 : 20 * log10(a));
}

#ifdef __WIN32__
static inline void MoveTo(HDC hdc, int X, int Y)
{
  MoveToEx(hdc, X, Y, NULL);
}
#endif

void PaintMainWindow(HWND hWnd)
{
  const char *xaxis[] = { "0", "pi / 4", "pi / 2", "3 * pi / 4", "pi" };
  PAINTSTRUCT ps;
  RECT r;
  int nOldMapMode, i;
  HPEN hBlackPen, hBluePen, hRedPen, hOldPen;
  HRGN hClipRgn;
  unsigned uOldTextAlign;
  char buffer[80];
  BeginPaint(hWnd, &ps);
  if(fDoPaint)
  {
    nOldMapMode = SetMapMode(ps.hdc, MM_TEXT);
    hBlackPen = CreatePen(PS_SOLID, 1, RGB(0, 0, 0));
    hBluePen = CreatePen(PS_SOLID, 3, RGB(0, 0, 255));
    hRedPen = CreatePen(PS_SOLID, 3, RGB(255, 0, 0));
    hOldPen = (HPEN)SelectObject(ps.hdc, (HANDLE)hBlackPen);
    GetClientRect(hWnd, &r);
    if(filtertype != OddDifferentiator)
    {
      r.left += 40;
      r.right -= 20;
      r.top += 20;
      r.bottom -= 30;
      SetScreen(r.left, r.top, r.right, r.bottom);
      SetWorld(0, MinY, M_PI, MaxY);
      uOldTextAlign = SetTextAlign(ps.hdc, TA_CENTER | TA_TOP);
      for(i = 0; i <= 4; i++)
      {
        MoveTo(ps.hdc, World2ScrX(M_PI / 4 * i), World2ScrY(MinY));
        LineTo(ps.hdc, World2ScrX(M_PI / 4 * i), World2ScrY(MaxY));
        TextOut(ps.hdc, World2ScrX(M_PI / 4 * i), r.bottom + 5, xaxis[i], strlen(xaxis[i]));
      }
      SetTextAlign(ps.hdc, TA_RIGHT | TA_BASELINE);
      MoveTo(ps.hdc, World2ScrX(0), World2ScrY(MinY));
      LineTo(ps.hdc, World2ScrX(M_PI), World2ScrY(MinY));
      sprintf(buffer, "%lg", (double)MinY);
      TextOut(ps.hdc, r.left - 5, World2ScrY(MinY), buffer, strlen(buffer));
      for(i = floor(MinY / 10) + 1; i <= floor(MaxY / 10); i++)
      {
        MoveTo(ps.hdc, World2ScrX(0), World2ScrY(i * 10));
        LineTo(ps.hdc, World2ScrX(M_PI), World2ScrY(i * 10));
        sprintf(buffer, "%i", i * 10);
        TextOut(ps.hdc, r.left - 5, World2ScrY(i * 10), buffer, strlen(buffer));
      }
      MoveTo(ps.hdc, World2ScrX(0), World2ScrY(MaxY));
      LineTo(ps.hdc, World2ScrX(M_PI), World2ScrY(MaxY));
      sprintf(buffer, "%lg", (double)MaxY);
      TextOut(ps.hdc, r.left - 5, World2ScrY(MaxY), buffer, strlen(buffer));
      hClipRgn = CreateRectRgn(r.left, r.top, r.right + 1, r.bottom + 1);
      SelectClipRgn(ps.hdc, hClipRgn);
      SelectObject(ps.hdc, hRedPen);
      MoveTo(ps.hdc, World2ScrX(0), World2ScrY(lnMFIR(H, 0)));
      for(i = r.left + 1; i <= r.right; i++)
        LineTo(ps.hdc, i, World2ScrY(lnMFIR(H, Scr2WorldX(i))));
      SelectObject(ps.hdc, hBluePen);
      for(i = 1; i <= GetBandsNo(FIR); i++)
      {
        double y;
        y = Eq(FIR[i].GetTrans(), 0) ? MinY : 20 * log10(FIR[i].GetTrans());
        MoveTo(ps.hdc, World2ScrX(FIR[i].GetLow()), World2ScrY(y));
        LineTo(ps.hdc, World2ScrX(FIR[i].GetHigh()), World2ScrY(y));
      }
    }
    else
    {
      r.left += 70;
      r.right -= 20;
      r.top += 20;
      r.bottom -= 30;
      SetScreen(r.left, r.top, r.right, r.bottom);
      SetWorld(0, 0, M_PI, M_PI);
      uOldTextAlign = SetTextAlign(ps.hdc, TA_CENTER | TA_TOP);
      for(i = 0; i <= 4; i++)
      {
        MoveTo(ps.hdc, World2ScrX(M_PI / 4 * i), World2ScrY(0));
        LineTo(ps.hdc, World2ScrX(M_PI / 4 * i), World2ScrY(M_PI));
        TextOut(ps.hdc, World2ScrX(M_PI / 4 * i), r.bottom + 5, xaxis[i], strlen(xaxis[i]));
      }
      SetTextAlign(ps.hdc, TA_RIGHT | TA_BASELINE);
      for(i = 0; i <= 4; i++)
      {
        MoveTo(ps.hdc, World2ScrX(0), World2ScrY(M_PI / 4 * i));
        LineTo(ps.hdc, World2ScrX(M_PI), World2ScrY(M_PI / 4 * i));
        TextOut(ps.hdc, r.left - 5, World2ScrY(M_PI / 4 * i), xaxis[i], strlen(xaxis[i]));
      }
      hClipRgn = CreateRectRgn(r.left, r.top, r.right + 1, r.bottom + 1);
      SelectClipRgn(ps.hdc, hClipRgn);
      SelectObject(ps.hdc, hRedPen);
      MoveTo(ps.hdc, World2ScrX(0), World2ScrY(MFIR(H, 0)));
      for(i = r.left + 1; i <= r.right; i++)
        LineTo(ps.hdc, i, World2ScrY(MFIR(H, Scr2WorldX(i))));
      SelectObject(ps.hdc, hBluePen);
      MoveTo(ps.hdc, World2ScrX(0), World2ScrY(0));
      LineTo(ps.hdc, World2ScrX(FIR[1].GetHigh()), World2ScrY(FIR[1].GetHigh()));
    }
    SetTextAlign(ps.hdc, uOldTextAlign);
    SelectObject(ps.hdc, (HANDLE)hOldPen);
    DeleteObject((HANDLE)hBlackPen);
    DeleteObject((HANDLE)hBluePen);
    DeleteObject((HANDLE)hRedPen);
    DeleteObject((HANDLE)hClipRgn);
    SetMapMode(ps.hdc, nOldMapMode);
  }
  EndPaint(hWnd, &ps);
}

LRESULT CALLBACK _export MainWndProc(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam)
{
  int i, j;
  char buffer[256];
  switch (wMsg)
  {
    case WM_COMMAND:
      switch (wParam)
      {
        case IDM_EXIT:
          PostMessage(hWnd, WM_CLOSE, 0, 0);
          return (0);
        case IDM_NEW:
          if(DialogBox(hInst, MAKEINTRESOURCE(1001), hWnd, DlgProcInstance(GetFIRTypeDlgProc)))
          {
            if(iFilterType == 2)
            {
              if(iFilterLength % 2 == 0)
                iFilterLength++;
              filtertype = OddDifferentiator;
            }
            else
              filtertype = iFilterLength % 2 ?
                iFilterType == 1 ? OddAntysymetrical : OddSymetrical :
                iFilterType == 1 ? EvenAntysymetrical : EvenSymetrical;
            j = iFilterType == 2 ? 1003 : 1002;
            FIR.SetNoBands(iFilterBandsNo);
            for(i = 1; i <= iFilterBandsNo; i++)
            {
              if(!DialogBoxParam(hInst, MAKEINTRESOURCE(j), hWnd, DlgProcInstance(iFilterType == 2 ? GetDiffDlgProc : GetBandDlgProc), i))
                return (0);
              FIR[i] = BandInfo(fBandData[0], fBandData[1], fBandData[3], fBandData[2]);
            }
            if(pszFileName)
              delete pszFileName;
            pszFileName = new char[sizeof(pcszUntitled)];
            strcpy(pszFileName, pcszUntitled);
            strcpy(buffer, "Projektowany filtr: ");
            strcat(buffer, pszFileName);
            SendMessage(hWnd, WM_SETTEXT, 0, (LPARAM)(LPCSTR)buffer);
            EnableMenuItem(GetMenu(hWnd), IDM_START, MF_BYCOMMAND | MF_ENABLED);
            EnableMenuItem(GetMenu(hWnd), IDM_SAVE, MF_BYCOMMAND | MF_ENABLED);
            EnableMenuItem(GetMenu(hWnd), IDM_SAVEAS, MF_BYCOMMAND | MF_ENABLED);
            fDoPaint = 0;
            InvalidateRect(hWnd, NULL, 1);
            EnableMenuItem(GetMenu(hMainWnd), IDM_COEFFS, MF_BYCOMMAND | MF_GRAYED);
            EnableMenuItem(GetMenu(hMainWnd), IDM_PRINT, MF_BYCOMMAND | MF_GRAYED);
            SendMessage(hWnd, WM_SETTEXT, 0, (LPARAM)(LPCSTR)pcszAppName);
          }
          return (0);
        case IDM_SAVE:
          if(strcmp(pszFileName, pcszUntitled) == 0)
          {
            strcpy(buffer, pcszUntitled);
            if(SaveFileName(buffer, sizeof(buffer), OFN_OVERWRITEPROMPT))
              SaveFile(buffer);
          }
          else
            SaveFile(pszFileName);
          return (0);
        case IDM_SAVEAS:
          strcpy(buffer, pszFileName);
          if(SaveFileName(buffer, sizeof(buffer)))
            if(FileExist(buffer))
            {
              char alex[80];
              sprintf(alex, "Plik %s już istnieje. Nadpisac ?", buffer);
              MessageBeep(MB_ICONQUESTION);
              if(MessageBox(hWnd, alex, NULL, MB_ICONQUESTION | MB_OKCANCEL | MB_DEFBUTTON2) == IDOK)
                SaveFile(buffer);
            }
            else
              SaveFile(buffer);
          return (0);
        case IDM_OPEN:
          if(OpenFileName(buffer, sizeof(buffer)))
          {
            OpenFile(buffer);
            fDoPaint = 0;
            InvalidateRect(hWnd, NULL, 1);
            EnableMenuItem(GetMenu(hMainWnd), IDM_COEFFS, MF_BYCOMMAND | MF_GRAYED);
            EnableMenuItem(GetMenu(hMainWnd), IDM_PRINT, MF_BYCOMMAND | MF_GRAYED);
          }
          return (0);
        case IDM_SEARCHMET:
          DialogBox(hInst, MAKEINTRESOURCE(1004), hWnd, DlgProcInstance(GetSearchTypeDlgProc));
          return (0);
        case IDM_MAXITER:
          DialogBox(hInst, MAKEINTRESOURCE(1005), hWnd, DlgProcInstance(GetMaxIterDlgProc));
          return (0);
        case IDM_START:
          hCurrDialog = CreateDialog(hInst, MAKEINTRESOURCE(1006), hWnd, lpfnInstIterDlgProc);
          InitRemez(FIR, iFilterLength, filtertype);
          uIteration = 1;
          SetDlgItemInt(hCurrDialog, D1006_STATIC1, 1, 0);
          sprintf(buffer, "%lg", fabs(Delta));
          SetDlgItemText(hCurrDialog, D1006_STATIC2, buffer);
          sprintf(buffer, "%lg", (double)Q);
          SetDlgItemText(hCurrDialog, D1006_STATIC3, buffer);
          BkgrProc = BackgroundTask;
          return (0);
        case IDM_GRID:
          DialogBox(hInst, MAKEINTRESOURCE(1007), hWnd, DlgProcInstance(GetGridDlgProc));
          return (0);
        case IDM_GETQ:
          DialogBox(hInst, MAKEINTRESOURCE(1008), hWnd, DlgProcInstance(GetReqQDlgProc));
          return (0);
        case IDM_COEFFS:
          DialogBox(hInst, MAKEINTRESOURCE(1009), hWnd, DlgProcInstance(CoeffsDlgProc));
          return (0);
        case IDM_PRINT:
          SaveOutput("PRN");
          return (0);
        case IDM_ABOUT:
          DialogBox(hInst, MAKEINTRESOURCE(1010), hWnd, DlgProcInstance(AboutDlgProc));
          return (0);
      }
      break;
    case WM_DESTROY:
      PostQuitMessage(0);
      return (0);
    case WM_PAINT:
      PaintMainWindow(hWnd);
      return (0);
  }
  return (DefWindowProc(hWnd, wMsg, wParam, lParam));
}

static int InitInstance(HINSTANCE hInst, int nShow)
{
  ::hInst = hInst;
  hMainWnd = CreateWindow(pcszClassName, pcszAppName, WS_OVERLAPPEDWINDOW,
               CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
               NULL, NULL, hInst, NULL);
  if(!hMainWnd)
    return (0);
  hCurrAccel = LoadAccelerators(hInst, MAKEINTRESOURCE(3001));
  ShowWindow(hMainWnd, nShow);
  UpdateWindow(hMainWnd);
  lpfnInstIterDlgProc = (DLGPROC_t)MakeProcInstance((FARPROC)IterDlgProc, hInst);
  return (1);
}

static int InitApp(HINSTANCE hInst)
{
  WNDCLASS wc;
  wc.style         = CS_HREDRAW | CS_VREDRAW;
  wc.lpfnWndProc   = MainWndProc;
  wc.cbClsExtra    = 0;
  wc.cbWndExtra    = 0;
  wc.hInstance     = hInst;
  wc.hIcon         = LoadIcon(NULL, IDI_APPLICATION);
  wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
  wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
  wc.lpszMenuName  = MAKEINTRESOURCE(2001);
  wc.lpszClassName = pcszClassName;
  return (RegisterClass(&wc));
}

static int ExitInst(void)
{
  FreeProcInstance((FARPROC)lpfnInstIterDlgProc);
  return (1);
}

int PASCAL WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR,
                   int nShow)
{
  MSG msg;
  if(!hPrev && !InitApp(hInst))
    return (1);
  if(!InitInstance(hInst, nShow))
    return (1);
  while(1)
  {
    if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
      if(msg.message == WM_QUIT)
        break;
      else
      {
        if(!hCurrDialog || !IsDialogMessage(hCurrDialog, &msg))
          if(!TranslateAccelerator(hMainWnd, hCurrAccel, &msg))
          {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
          }
      }
    else
      if(BkgrProc)
        (*BkgrProc)();
      else
        WaitMessage();
  }
  ExitInst();
  return (msg.wParam);
}
